home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / read_rc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-16  |  28.4 KB  |  1,056 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: read_rc.c,v 5.16 1993/05/16 20:59:14 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.16 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: read_rc.c,v $
  17.  * Revision 5.16  1993/05/16  20:59:14  syd
  18.  * fix not closing file
  19.  * From: Syd
  20.  *
  21.  * Revision 5.15  1993/05/08  20:25:33  syd
  22.  * Add sleepmsg to control transient message delays
  23.  * From: Syd
  24.  *
  25.  * Revision 5.14  1993/05/08  20:06:15  syd
  26.  * add sleepinterval to valid options
  27.  *
  28.  * Revision 5.13  1993/05/08  18:56:16  syd
  29.  * created a new elmrc variable named "readmsginc".  This specifies an
  30.  * increment by which the message count is updated.  If this variable is
  31.  * set to, say, 25, then the message count will only be updated every 25
  32.  * messages, displaying 0, 25, 50, 75, and so forth.  The default value
  33.  * of 1 will cause Elm to behave exactly as it currently does in PL21.
  34.  * From: Eric Peterson <epeterso@encore.com>
  35.  *
  36.  * Revision 5.12  1993/02/03  19:06:31  syd
  37.  * Remove extra strchr/strcat/strcpy et al declarations
  38.  * From: Syd
  39.  *
  40.  * Revision 5.11  1993/01/20  04:01:07  syd
  41.  * Adds a new integer parameter builtinlines.
  42.  * if (builtinlines < 0) and (the length of the message < LINES on
  43.  *       screen + builtinlines) use internal.
  44.  * if (builtinlines > 0) and (length of message < builtinlines)
  45.  *     use internal pager.
  46.  * if (builtinlines = 0) or none of the above conditions hold, use the
  47.  * external pager if defined.
  48.  * From: "John P. Rouillard" <rouilj@ra.cs.umb.edu>
  49.  *
  50.  * Revision 5.10  1992/11/26  00:46:13  syd
  51.  * changes to first change screen back (Raw off) and then issue final
  52.  * error message.
  53.  * From: Syd
  54.  *
  55.  * Revision 5.9  1992/11/24  01:44:18  syd
  56.  * Add raw/no tite stuff around directory create questions
  57.  * From: Syd via bug report from ade@clark.edu
  58.  *
  59.  * Revision 5.8  1992/11/07  16:27:33  syd
  60.  * Fix where elm duplicates the entry's from the global elm.rc.
  61.  * It will however still copy the global weedout headers to your local
  62.  * elmrc if they where not already in it.
  63.  * From: janw@fwi.uva.nl (Jan Wortelboer)
  64.  *
  65.  * Revision 5.7  1992/10/24  13:44:41  syd
  66.  * There is now an additional elmrc option "displaycharset", which
  67.  * sets the charset supported on your terminal. This is to prevent
  68.  * elm from calling out to metamail too often.
  69.  * Plus a slight documentation update for MIME composition (added examples)
  70.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  71.  *
  72.  * Revision 5.6  1992/10/24  13:35:39  syd
  73.  * changes found by using codecenter on Elm 2.4.3
  74.  * From: Graham Hudspith <gwh@inmos.co.uk>
  75.  *
  76.  * Revision 5.5  1992/10/17  22:58:57  syd
  77.  * patch to make elm use (or in my case, not use) termcap/terminfo ti/te.
  78.  * From: Graham Hudspith <gwh@inmos.co.uk>
  79.  *
  80.  * Revision 5.4  1992/10/17  22:42:24  syd
  81.  * Add flags to read_rc to support command line overrides of the option.
  82.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  83.  *
  84.  * Revision 5.3  1992/10/17  22:25:29  syd
  85.  * TEXT_SORT was supported, but UNRECOGNIZED
  86.  * From: ls@dmicvx.dmi.min.dk  (Lennart Sorth)
  87.  *
  88.  * Revision 5.2  1992/10/11  00:59:39  syd
  89.  * Fix some compiler warnings that I receive compiling Elm on my SVR4
  90.  * machine.
  91.  * From: Tom Moore <tmoore@fievel.DaytonOH.NCR.COM>
  92.  *
  93.  * Revision 5.1  1992/10/03  22:58:40  syd
  94.  * Initial checkin as of 2.4 Release at PL0
  95.  *
  96.  *
  97.  ******************************************************************************/
  98.  
  99. /** This file contains programs to allow the user to have a .elm/elmrc file
  100.     in their home directory containing any of the following: 
  101.  
  102.     fullname= <username string>
  103.     maildir = <directory>
  104.     tmpdir  = <directory>
  105.     sentmail = <file>
  106.     editor  = <editor>
  107.     receviedmail= <file>
  108.     calendar= <calendar file name>
  109.     shell   = <shell>
  110.     print   = <print command>
  111.     weedout = <list of headers to weed out>
  112.     prefix  = <copied message prefix string>
  113.     pager   = <command to use for displaying messages>
  114.     configoptions = <list of letters to use for options menu>
  115.     precedences = <list of delivery precedences>
  116.     
  117.     escape  = <single character escape, default = '~' >
  118.  
  119. --
  120.     signature = <.signature file for all outbound mail>
  121. OR:
  122.     localsignature = <.signature file for local mail>
  123.     remotesignature = <.signature file for non-local mail>
  124. --
  125.  
  126.     bounceback= <hop count threshold, or zero to disable>
  127.     readmsginc = <new folder message count display increment>
  128.     sleepmsg = time to 'sleep' while displaying transient messages
  129.     timeout = <seconds for main menu timeout or zero to disable>
  130.     userlevel = <0=amateur, 1=okay, 2 or greater = expert!>
  131.  
  132.     sortby  = <sent, received, from, size, subject, mailbox, status>
  133.     alias_sortby  = <alias, name>
  134.  
  135.     alternatives = <list of addresses that forward to us>
  136.  
  137.     builtinlines = <use builtin pager if message shorter than # lines>
  138.  
  139.     and/or the logical arguments:
  140.     
  141.     autocopy    [on|off]
  142.     askcc        [on|off]
  143.     copy        [on|off]    
  144.     resolve     [on|off]
  145.     weed        [on|off]
  146.     noheader    [on|off]
  147.     titles      [on|off]
  148.     savebyname  [on|off]
  149.     forcename   [on|off]
  150.     movepage    [on|off]
  151.     pointnew    [on|off]
  152.     hpkeypad    [on|off]
  153.     hpsoftkeys  [on|off]
  154.     alwayskeep  [on|off]
  155.     alwaysstore [on|off]
  156.     alwaysdel   [on|off]
  157.     arrow        [on|off]
  158.     menus        [on|off]
  159.     metoo        [on|off]
  160.     forms        [on|off]
  161.     names        [on|off]
  162.     ask        [on|off]
  163.     keepempty   [on|off]
  164.     promptafter [on|off]
  165.     sigdashes   [on|off]
  166.     usetite        [on|off]
  167.  
  168.  
  169.     Lines starting with '#' are considered comments and are not checked
  170.     any further!
  171.  
  172. **/
  173.  
  174. #define SAVE_OPTS
  175. #include <ctype.h>
  176. #include "headers.h"
  177. #include "save_opts.h"
  178. #include "s_elm.h"
  179. #include <errno.h>
  180.  
  181. #ifdef BSD
  182. #undef tolower
  183. #endif
  184.  
  185. extern opts_menu *find_cfg_opts();
  186. extern int errno;
  187.  
  188. char  *error_description(), *shift_lower();
  189.  
  190. #define  metachar(c)    (c == '+' || c == '%' || c == '=')
  191. #ifndef ok_rc_char
  192. #define ok_rc_char(c)   (isalnum(c) || c == '-' || c == '_')
  193. #endif
  194.  
  195.  
  196. #define ASSIGNMENT      0
  197. #define WEEDOUT        1
  198. #define ALTERNATIVES    2
  199.  
  200. #define SYSTEM_RC    0
  201. #define LOCAL_RC    1
  202.  
  203. static int lineno = 0;
  204. static int errors = 0;
  205.  
  206. read_rc_file()
  207. {
  208.     /** this routine does all the actual work of reading in the
  209.         .rc file... **/
  210.  
  211.     FILE *file;
  212.     char buffer[SLEN], filename[SLEN], *cp, 
  213.              temp[SLEN]; /* for when an option is run through expandenv */
  214.     int  i, ch, len, err;
  215.  
  216.     /* Establish some defaults in case elmrc is incomplete or not there.
  217.      * Defaults for other elmrc options were established in their
  218.      * declaration - in elm.h.  And defaults for sent_mail and recvd_mail
  219.      * are established after the elmrc is read in since these default
  220.      * are based on the folders directory name, which may be given
  221.      * in the emrc.
  222.      * Also establish alternative_editor here since it is based on
  223.      * the default editor and not on the one that might be given in the
  224.      * elmrc.
  225.      */
  226.      
  227.     default_weedlist();
  228.  
  229.     errors = 0;
  230.     alternative_addresses = NULL;     /* none yet! */
  231.  
  232.     raw_local_signature[0] = raw_remote_signature[0] =
  233.         local_signature[0] = remote_signature[0] =
  234.         raw_recvdmail[0] = raw_sentmail[0] = 
  235.         allowed_precedences[0] = '\0';
  236.         /* no defaults for those */
  237.  
  238.  
  239.     strcpy(raw_shell, ((cp = getenv("SHELL")) == NULL)? default_shell : cp);
  240.     strcpy(temp, raw_shell);
  241.     expand_env(shell, temp);
  242.  
  243.     strcpy(raw_pager, ((cp = getenv("PAGER")) == NULL)? default_pager : cp);
  244.     strcpy(temp, raw_pager);
  245.     expand_env(pager, temp);
  246.  
  247.     strcpy(raw_editor, ((cp = getenv("EDITOR")) == NULL)? default_editor:cp);
  248.  
  249.     strcpy(temp_dir, ((cp = getenv("TMPDIR")) == NULL)? default_temp:cp);
  250.     if (temp_dir[strlen (temp_dir)-1] != '/')
  251.                 strcat(temp_dir, "/");
  252.  
  253.     strcpy(alternative_editor, raw_editor);
  254.     strcpy(temp, raw_editor);
  255.     expand_env(editor, temp);
  256.  
  257.     strcpy(raw_printout, default_printout);
  258.     strcpy(temp, raw_printout);
  259.     expand_env(printout, temp);
  260.  
  261.     sprintf(raw_folders, "~/%s", default_folders);
  262.     strcpy(temp, raw_folders);
  263.     expand_env(folders, temp);
  264.  
  265.     sprintf(raw_calendar_file, "~/%s", dflt_calendar_file);
  266.     strcpy(temp, raw_calendar_file);
  267.     expand_env(calendar_file, temp);
  268.  
  269.     strcpy(e_editor, emacs_editor);
  270.     strcpy(v_editor, default_editor);
  271.  
  272.     strcpy(raw_printout, default_printout);
  273.     strcpy(printout, raw_printout);
  274.  
  275.     sprintf(raw_folders, "%s/%s", home, default_folders);
  276.     strcpy(folders, raw_folders);
  277.  
  278.     sprintf(raw_calendar_file, "%s/%s", home, dflt_calendar_file);
  279.     strcpy(calendar_file, raw_calendar_file);
  280.  
  281. #ifdef MIME
  282.     strcpy(charset, default_charset);
  283.     strcpy(charset_compatlist, COMPAT_CHARSETS);
  284.     strcpy(display_charset, default_display_charset);
  285.     strcpy(text_encoding, default_encoding);
  286. #endif
  287.  
  288.     /* see if the user has a $HOME/.elm directory */
  289.     sprintf(filename, "%s/.elm", home);
  290.     if (access(filename, 00) == -1) {
  291.       if(batch_only)  {
  292.         printf(catgets(elm_msg_cat, ElmSet, ElmBatchDirNotice, "\nNotice:\
  293. \nThis version of ELM requires the use of a .elm directory to store your\
  294. \nelmrc and alias files. I'd like to create the directory .elm for you\
  295. \nand set it up, but I can't in \"batch mode\".\
  296. \nPlease run ELM in \"normal mode\" first.\n"));
  297.         exit(0);
  298.       }
  299.  
  300.       Raw(ON | NO_TITE);
  301.       MCprintf(catgets(elm_msg_cat, ElmSet, ElmDirNotice, "\n\rNotice:\
  302. \n\rThis version of ELM requires the use of a .elm directory in your home\
  303. \n\rdirectory to store your elmrc and alias files. Shall I create the\
  304. \n\rdirectory .elm for you and set it up (%c/%c/q)? %c%c"),
  305.         *def_ans_yes, *def_ans_no, *def_ans_no, BACKSPACE);
  306.  
  307.       fflush(stdout);
  308.       ch=getchar();
  309.       if (isupper(ch)) ch = tolower(ch);
  310.       if (ch == '\n' || ch == '\r') /* they took the default by pressing cr */
  311.         ch = *def_ans_no;
  312.  
  313.       if (ch == *def_ans_no) {
  314.         printf(catgets(elm_msg_cat, ElmSet, ElmDirNoticeNo,
  315. "No.\n\rVery well. I won't create it.\n\rBut, you may run into difficulties later.\n\r"));
  316.         if (sleepmsg > 0)
  317.         sleep(sleepmsg * 2);
  318.       }
  319.       else if (ch == *def_ans_yes) {
  320.         printf(catgets(elm_msg_cat, ElmSet, ElmDirNoticeYes,
  321.         "Yes.\n\rGreat! I'll do it now.\n\r"));
  322.         create_new_elmdir();
  323.       }
  324.       else {
  325.         printf(catgets(elm_msg_cat, ElmSet, ElmDirNoticeQuit,
  326.             "Quit.\n\rOK.  Bailing out of ELM.\n\r"));
  327.         Raw(OFF | NO_TITE);
  328.         exit(0);
  329.       }
  330.       Raw(OFF | NO_TITE);
  331.     }
  332.  
  333.     /* try system-wide rc file */
  334.     file = fopen(system_rc_file, "r");
  335.     do_rc(file, SYSTEM_RC);
  336.     fclose(file);
  337.  
  338.     /* Look for the elmrc file */
  339.     sprintf(filename, "%s/%s", home, elmrcfile);
  340.     if ((file = fopen(filename, "r")) == NULL) {
  341.       dprint(2, (debugfile, "Warning:User has no \".elm/elmrc\" file\n\n"));
  342.  
  343.       /* look for old-style .elmrc file in $HOME */
  344.       sprintf(filename, "%s/.elmrc", home);
  345.       if (access(filename, 00) != -1) {
  346.         move_old_files_to_new();
  347.  
  348.         /* try to open elmrc file again */
  349.         sprintf(filename, "%s/%s", home, elmrcfile);
  350.         if((file = fopen(filename, "r")) == NULL) {
  351.           err = errno;
  352.           dprint(2, (debugfile,
  353.         "Warning: could not open new \".elm/elmrc\" file.\n"));
  354.           dprint(2, (debugfile, "** %s **\n", error_description(err)));
  355.           printf(catgets(elm_msg_cat, ElmSet, ElmCouldNotOpenNewElmrc,
  356.         "Warning: could not open new \".elm/elmrc\" file! Using default parameters.\n\r"));
  357.           if (sleepmsg > 0)
  358.             sleep(sleepmsg * 2);
  359.         }
  360.       }
  361.     }
  362.     if (file != NULL) {
  363.         do_rc(file, LOCAL_RC);
  364.       fclose(file);
  365.     }
  366.  
  367. /* validate/correct config_options string */
  368.  
  369.     if (config_options[0]) {
  370.         register char *s, *t;
  371.         register opts_menu *o;
  372.         s = shift_lower(config_options);
  373.         for (t = config_options; *s; ++s) {
  374.         if (*s == '_' || *s == '^') {
  375.             *t++ = *s;
  376.             continue;
  377.         }
  378.         o = find_cfg_opts(*s);
  379.         if (o != NULL)
  380.             *t++ = *s; /* silently remove invalid options */
  381.         }
  382.         *t = '\0';
  383.     }
  384.     strcpy(buffer, raw_folders);
  385.     expand_env(folders, buffer);
  386.  
  387.     strcpy(buffer, temp_dir);
  388.     expand_env(temp_dir, buffer);
  389.     if (temp_dir[strlen (temp_dir)-1] != '/')
  390.         strcat(temp_dir, "/");
  391.  
  392.     strcpy(buffer, raw_shell);
  393.     expand_env(shell, buffer);
  394.  
  395.     strcpy(buffer, raw_editor);
  396.     expand_env(editor, buffer);
  397.  
  398.     strcpy(buffer, raw_calendar_file);
  399.     expand_env(calendar_file, buffer);
  400.  
  401.     strcpy(buffer, raw_printout);
  402.     expand_env(printout, buffer);
  403.  
  404.     strcpy(buffer, raw_pager);
  405.     expand_env(pager, buffer);
  406.     if (equal(pager, "builtin+") || equal(pager, "internal+"))
  407.         clear_pages++;
  408.  
  409.     strcpy(buffer, raw_local_signature);
  410.     expand_env(local_signature, buffer);
  411.  
  412.     strcpy(buffer, raw_remote_signature);
  413.     expand_env(remote_signature, buffer);
  414.  
  415.     if (equal(local_signature, remote_signature) &&
  416.         (equal(shift_lower(local_signature), "on") ||
  417.         equal(shift_lower(local_signature), "off"))) {
  418.         errors++;
  419.  
  420.         printf(catgets(elm_msg_cat, ElmSet, ElmSignatureObsolete,
  421.     "\"signature\" used in obsolete way in .elm/elmrc file. Ignored!\n\r\
  422. \t(Signature should specify the filename to use rather than on/off.)\n\r\n"));
  423.  
  424.         raw_local_signature[0] = raw_remote_signature[0] =
  425.         local_signature[0] = remote_signature[0] = '\0';
  426.     }
  427.  
  428.     if (hp_softkeys) hp_terminal=TRUE;    /* must be set also! */
  429.  
  430.     allow_forms = (allow_forms?MAYBE:NO);
  431.     if (bounceback > MAX_HOPS) {
  432.         errors++;
  433.         printf(catgets(elm_msg_cat, ElmSet, ElmBouncebackGTMaxhops,
  434.     "Warning: bounceback is set to greater than %d (max-hops). Ignored.\n\r"),
  435.              MAX_HOPS);
  436.         bounceback = 0;
  437.     }
  438.  
  439.     if ((timeout != 0) && (timeout < 10)) {
  440.         errors++;
  441.         printf(catgets(elm_msg_cat, ElmSet, ElmTimeoutLTTen,
  442.          "Warning: timeout is set to less than 10 seconds. Ignored.\n\r"));
  443.         timeout = 0;
  444.     }
  445.  
  446.     if (readmsginc < 1) {
  447.         errors++;
  448.         printf(catgets(elm_msg_cat, ElmSet, ElmReadMessageIncrement,
  449.         "Warning: readmsginc is set to less than 1.  Ignored.\n\r"));
  450.         readmsginc = 1;
  451.     }
  452.  
  453.     if (sleepmsg < 0) {
  454.         errors++;
  455.         printf(catgets(elm_msg_cat, ElmSet, ElmSleepMessageInvalid,
  456.         "Warning: sleepmsg is set to less than 0.  Setting to 0.\n\r"));
  457.         sleepmsg = 0;
  458.     }
  459.  
  460.     /* see if the user has a folders directory */
  461.     if (access(folders, 00) == -1) {
  462.       if(batch_only)  {
  463.         printf(catgets(elm_msg_cat, ElmSet, ElmBatchNoticeFoldersDir, "\n\
  464. Notice:\n\
  465. ELM requires the use of a folders directory to store your mail folders in.\n\
  466. I'd like to create the directory %s for you,\n\
  467. but I can't in \"batch mode\". Please run ELM in \"normal mode\" first.\n"),
  468.         folders);
  469.         exit(0);
  470.       }
  471.  
  472.       Raw( ON | NO_TITE );
  473.       MCprintf(catgets(elm_msg_cat, ElmSet, ElmNoticeFoldersDir,"\n\rNotice:\n\r\
  474. ELM requires the use of a folders directory to store your mail folders in.\n\r\
  475. Shall I create the directory %s for you (%c/%c/q)? %c%c"),
  476.         folders, *def_ans_yes, *def_ans_no, *def_ans_yes, BACKSPACE);
  477.  
  478.       fflush(stdout);
  479.       ch=getchar();
  480.       if (isupper(ch)) ch = tolower(ch);
  481.       if (ch == '\n' || ch == '\r') /* they took the default by pressing cr */
  482.         ch = *def_ans_yes;
  483.  
  484.       if (ch == *def_ans_no) {
  485.         printf(catgets(elm_msg_cat, ElmSet, ElmDirNoticeNo,
  486. "No.\n\rVery well. I won't create it.\n\rBut, you may run into difficulties later.\n\r"));
  487.         if (sleepmsg > 0)
  488.             sleep(sleepmsg * 2);
  489.       }
  490.       else if (ch == *def_ans_yes) {
  491.         printf(catgets(elm_msg_cat, ElmSet, ElmDirNoticeYes,
  492.         "Yes.\n\rGreat! I'll do it now.\n\r"));
  493.         create_new_folders();
  494.       }
  495.       else {
  496.         printf(catgets(elm_msg_cat, ElmSet, ElmDirNoticeQuit,
  497.             "Quit.\n\rOK.  Bailing out of ELM.\n\r"));
  498.         Raw(OFF | NO_TITE);
  499.         exit(0);
  500.       }
  501.       Raw( OFF | NO_TITE );
  502.     }
  503.  
  504.     /* If recvd_mail or sent_mail havent't yet been established in
  505.      * the elmrc, establish them from their defaults.
  506.      * Then if they begin with a metacharacter, replace it with the
  507.      * folders directory name.
  508.      */
  509.     if(*raw_recvdmail == '\0') {
  510.       strcpy(raw_recvdmail, default_recvdmail);
  511.     }
  512.  
  513.     strcpy(buffer, raw_recvdmail);
  514.     expand_env(recvd_mail, buffer);
  515.  
  516.     if(metachar(recvd_mail[0])) {
  517.       strcpy(buffer, &recvd_mail[1]);
  518.       sprintf(recvd_mail, "%s/%s", folders, buffer);
  519.     }
  520.  
  521.     if(*raw_sentmail == '\0') {
  522.       sprintf(raw_sentmail, default_sentmail);
  523.       sprintf(sent_mail, default_sentmail);
  524.     }
  525.  
  526.     strcpy(buffer, raw_sentmail);
  527.     expand_env(sent_mail, buffer);
  528.  
  529.     if(metachar(sent_mail[0])) {
  530.       strcpy(buffer, &sent_mail[1]);
  531.       sprintf(sent_mail, "%s/%s", folders, buffer);
  532.     }
  533.  
  534.     if (debug > 10)     /** only do this if we REALLY want debug! **/
  535.       dump_rc_results();
  536.  
  537. }
  538.  
  539.  
  540. do_rc(file, lcl)
  541. FILE *file;
  542. int lcl;
  543. {
  544.     static int prev_type = 0;
  545.     int x;
  546.     char buffer[SLEN], word1[SLEN], word2[SLEN];
  547.  
  548.     if (!file) return;
  549.     lineno=0;
  550.  
  551.     while (x = mail_gets(buffer, SLEN, file)) {
  552.         lineno++;
  553.         no_ret(buffer);         /* remove return */
  554.         if (buffer[0] == '#'        /* comment       */
  555.          || x < 2)     /* empty line    */
  556.           continue;
  557.  
  558.         if(breakup(buffer, word1, word2) == -1)
  559.             continue;        /* word2 is null - let default value stand */
  560.  
  561.         if(strcmp(word1, "warnings") == 0)
  562.         continue;        /* grandfather old keywords */
  563.  
  564.         strcpy(word1, shift_lower(word1));    /* to lower case */
  565.         x = do_set(file, word1, word2, lcl);
  566.  
  567.         if (x == 0) {
  568.         if (prev_type == DT_ALT) {
  569.             alternatives(buffer);
  570.         } else if (prev_type == DT_WEE) {
  571.             weedout(buffer);
  572.         } else {
  573.             errors++;
  574.             printf(catgets(elm_msg_cat, ElmSet, ElmBadSortKeyInElmrc,
  575.       "I can't understand sort key \"%s\" in line %d in your \".elm/elmrc\" file\n\r"),
  576.             word1, lineno);
  577.         }
  578.         } else
  579.         prev_type = x;
  580.     }
  581. }
  582.  
  583. /*
  584.  * set the named parameter according to save_info structure.
  585.  * This routine may call itself (DT_SYN or DT_MLT).
  586.  * Also tags params that were set in "local" (personal) RC file
  587.  * so we know to save them back out in "o)ptions" screen.
  588.  * Uses an internal table to decode sort-by params...should be coupled
  589.  * with sort_name(), etc...but...
  590.  */
  591.  
  592. do_set(file, word1, word2, lcl)
  593. FILE *file;
  594. int lcl;
  595. char *word1, *word2;
  596. {
  597.     register int x, y;
  598.  
  599.     for (x=0; x < NUMBER_OF_SAVEABLE_OPTIONS; ++x) {
  600.         y = strcmp(word1, save_info[x].name);
  601.         if (y <= 0)
  602.         break;
  603.     }
  604.  
  605.     if (y != 0)
  606.         return(0);
  607.  
  608.     if (save_info[x].flags & FL_SYS && lcl == LOCAL_RC)
  609.         return(0);
  610.  
  611.     if (lcl == LOCAL_RC)
  612.         save_info[x].flags |= FL_LOCAL;
  613.  
  614.     switch (save_info[x].flags & DT_MASK) {
  615.         case DT_SYN:
  616.         return(do_set(file, SAVE_INFO_SYN(x), word2, lcl));
  617.  
  618.         case DT_MLT:
  619.         y=0;
  620.         { register char **s;
  621.         for (s = SAVE_INFO_MLT(x); *s; ++s)
  622.             y |= do_set(file, *s, word2, lcl);
  623.         }
  624.  
  625. /* a kludge that should be part of the "machine", but... */
  626.         if (equal(save_info[x].name, "alwaysleave")) {
  627.             always_store = !always_store;
  628.         }
  629.         return(y); /* we shouldn't "or" the values into "y" */
  630.  
  631.         case DT_STR:
  632.         strcpy(SAVE_INFO_STR(x), word2);
  633.         if (save_info[x].flags & FL_NOSPC) {
  634.             register char *s;
  635.             for (s = SAVE_INFO_STR(x); *s; ++s)
  636.             if (*s == '_') *s=' ';
  637.             }
  638.         break;
  639.  
  640.         case DT_CHR:
  641.         *SAVE_INFO_CHR(x) = word2[0];
  642.         break;
  643.  
  644.         case DT_NUM:
  645.         *SAVE_INFO_NUM(x) = atoi(word2);
  646.         break;
  647.  
  648.         case DT_BOL:
  649.         if (save_info[x].flags & FL_OR)
  650.             *SAVE_INFO_BOL(x) |= is_it_on(word2);
  651.         else if (save_info[x].flags & FL_AND)
  652.             *SAVE_INFO_BOL(x) &= is_it_on(word2);
  653.         else
  654.             *SAVE_INFO_BOL(x) = is_it_on(word2);
  655.         break;
  656.  
  657.         case DT_SRT:
  658.         { static struct { char *kw; int sv; } srtval[]={
  659.             {"sent", SENT_DATE},
  660.             {"received", RECEIVED_DATE},
  661.             {"recieved", RECEIVED_DATE},
  662.             {"rec", RECEIVED_DATE},
  663.             {"from", SENDER},
  664.             {"sender", SENDER},
  665.             {"size", SIZE},
  666.             {"lines", SIZE},
  667.             {"subject", SUBJECT},
  668.             {"mailbox", MAILBOX_ORDER},
  669.             {"folder", MAILBOX_ORDER},
  670.             {"status", STATUS},
  671.             {NULL, 0} };
  672.             char *s = word2;
  673.             int f;
  674.  
  675.             f = 1;
  676.             strcpy(word2, shift_lower(word2));
  677.             if (strncmp(s, "rev-", 4) == 0 ||
  678.             strncmp(s, "reverse-", 8) == 0) {
  679.             f = -f;
  680.             s = index(s, '-') + 1;
  681.             }
  682.  
  683.             for (y= 0; srtval[y].kw; y++) {
  684.             if (equal(s, srtval[y].kw))
  685.                 break;
  686.             }
  687.             if (srtval[y].kw) {
  688.             *SAVE_INFO_SRT(x) = f > 0 ? srtval[y].sv : -srtval[y].sv;
  689.             } else {
  690.             errors++;
  691.             printf(catgets(elm_msg_cat, ElmSet, ElmBadSortKeyInElmrc,
  692.       "I can't understand sort key \"%s\" in line %d in your \".elm/elmrc\" file\n\r"),
  693.                 word2, lineno);
  694.             }
  695.         }
  696.         break;
  697.  
  698.         case DT_ASR:
  699.         { static struct { char *kw; int sv; } srtval[]={
  700.             {"alias", ALIAS_SORT},
  701.             {"name", NAME_SORT},
  702.             {"text", TEXT_SORT},
  703.             {NULL, 0} };
  704.             char *s = word2;
  705.             int f;
  706.  
  707.             f = 1;
  708.             strcpy(word2, shift_lower(word2));
  709.             if (strncmp(s, "rev-", 4) == 0 ||
  710.             strncmp(s, "reverse-", 8) == 0) {
  711.             f = -f;
  712.             s = index(s, '-') + 1;
  713.             }
  714.  
  715.             for (y= 0; srtval[y].kw; y++) {
  716.             if (equal(s, srtval[y].kw))
  717.                 break;
  718.             }
  719.             if (srtval[y].kw) {
  720.             *SAVE_INFO_SRT(x) = f > 0 ? srtval[y].sv : -srtval[y].sv;
  721.             } else {
  722.             errors++;
  723.             printf(catgets(elm_msg_cat, ElmSet, ElmBadAliasSortInElmrc,
  724.     "I can't understand alias sort key \"%s\" in line %d in your \".elm/elmrc\" file\n\r"),
  725.                 word2, lineno);
  726.             }
  727.         }
  728.         break;
  729.  
  730.         case DT_ALT:
  731.         alternatives(word2);
  732.         break;
  733.  
  734.         case DT_WEE:
  735.         weedout(word2);
  736.         break;
  737.         }
  738.  
  739.     return(save_info[x].flags & DT_MASK);
  740. }
  741.     
  742. weedout(string)
  743. char *string;
  744. {
  745.     /** This routine is called with a list of headers to weed out.   **/
  746.  
  747.     char *strptr, *header;
  748.     register int i, len;
  749.  
  750.     strptr = string;
  751.  
  752.     while ((header = strtok(strptr, "\t ,\"'")) != NULL) {
  753.       if (strlen(header) > 0) {
  754.         if (! istrcmp(header, "*end-of-user-headers*")) break;
  755.         if (! istrcmp(header, "*clear-weed-list*")) {
  756.           weedlist[0] = "*end-of-defaults*";
  757.           weedcount = 1;
  758.         }
  759.         if (weedcount > MAX_IN_WEEDLIST) {
  760.           printf(catgets(elm_msg_cat, ElmSet, ElmTooManyWeedHeaders,
  761.         "Too many weed headers!  Leaving...\n\r"));
  762.           exit(1);
  763.         }
  764.         if ((weedlist[weedcount] = pmalloc(strlen(header) + 1)) == NULL) {
  765.           printf(catgets(elm_msg_cat, ElmSet, ElmTooManyWeedPmalloc,
  766.         "Too many weed headers! Out of memory!  Leaving...\n\r"));
  767.           exit(1);
  768.         }
  769.  
  770.         for (i=0, len = strlen(header); i< len; i++)
  771.           if (header[i] == '_') header[i] = ' ';
  772.  
  773.             if(!matches_weedlist(header)) {
  774.           strcpy(weedlist[weedcount], header);
  775.           weedcount++;
  776.         }
  777. /* since this used both for system defaults and user's */
  778.         if (equal(header, "*end-of-defaults*")) break;
  779.       }
  780.       strptr = NULL;
  781.     }
  782. }
  783.  
  784.  
  785. alternatives(string)
  786. char *string;
  787. {
  788.     /** This routine is called with a list of alternative addresses
  789.         that you may receive mail from (forwarded) **/
  790.  
  791.     char *strptr, *address;
  792.     struct addr_rec *current_record, *previous_record;
  793.  
  794.     previous_record = alternative_addresses;    /* start 'er up! */
  795.     /* move to the END of the alternative addresses list */
  796.  
  797.     if (previous_record != NULL)
  798.       while (previous_record->next != NULL)
  799.         previous_record = previous_record->next;
  800.  
  801.     strptr = (char *) string;
  802.  
  803.     while ((address = strtok(strptr, "\t ,\"'")) != NULL) {
  804.       if (previous_record == NULL) {
  805.         previous_record = (struct addr_rec *) pmalloc(sizeof 
  806.         *alternative_addresses);
  807.  
  808.         strcpy(previous_record->address, address);
  809.         previous_record->next = NULL;
  810.         alternative_addresses = previous_record;
  811.       }
  812.       else {
  813.         current_record = (struct addr_rec *) pmalloc(sizeof 
  814.         *alternative_addresses);
  815.       
  816.         strcpy(current_record->address, address);
  817.         current_record->next = NULL;
  818.         previous_record->next = current_record;
  819.         previous_record = current_record;
  820.       }
  821.       strptr = (char *) NULL;
  822.     }
  823. }
  824.  
  825. default_weedlist()
  826. {
  827.     /** Install the default headers to weed out!  Many gracious 
  828.         thanks to John Lebovitz for this dynamic method of 
  829.         allocation!
  830.     **/
  831.  
  832.     static char *default_list[] = { ">From", "In-Reply-To:",
  833.                "References:", "Newsgroups:", "Received:",
  834.                "Apparently-To:", "Message-Id:", "Content-Type:",
  835.                "Content-Length", "MIME-Version",
  836.                "Content-Transfer-Encoding",
  837.                "From", "X-Mailer:", "Status:",
  838.                "*end-of-defaults*", NULL
  839.              };
  840.  
  841.     for (weedcount = 0; default_list[weedcount] != (char *) 0;weedcount++){
  842.       if ((weedlist[weedcount] = 
  843.           pmalloc(strlen(default_list[weedcount]) + 1)) == NULL) {
  844.         printf(catgets(elm_msg_cat, ElmSet, ElmNoMemDefaultWeed,
  845.         "\nNot enough memory for default weedlist. Leaving.\n"));
  846.         leave(1);
  847.       }
  848.       strcpy(weedlist[weedcount], default_list[weedcount]);
  849.     }
  850. }
  851.  
  852. int
  853. matches_weedlist(buffer)
  854. char *buffer;
  855. {
  856.     /** returns true iff the first 'n' characters of 'buffer' 
  857.         match an entry of the weedlist **/
  858.     
  859.     register int i;
  860.  
  861.     for (i=0;i < weedcount; i++)
  862.       if (strincmp(buffer, weedlist[i], strlen(weedlist[i])) == 0) 
  863.         return(1);
  864.  
  865.     return(0);
  866. }
  867.  
  868. int
  869. breakup(buffer, word1, word2)
  870. char *buffer, *word1, *word2;
  871. {
  872.     /** This routine breaks buffer down into word1, word2 where 
  873.         word1 is alpha characters only, and there is an equal
  874.         sign delimiting the two...
  875.         alpha = beta
  876.         For lines with more than one 'rhs', word2 is set to the
  877.         entire string.
  878.         Return -1 if word 2 is of zero length, else 0.
  879.     **/
  880.  
  881.     register int i;
  882.     
  883.     for (i=0;buffer[i] != '\0' && ok_rc_char(buffer[i]); i++)
  884.       if (buffer[i] == '_')
  885.         word1[i] = '-';
  886.       else if (isupper(buffer[i]))
  887.         word1[i] = tolower(buffer[i]);
  888.       else
  889.         word1[i] = buffer[i];
  890.  
  891.     word1[i++] = '\0';    /* that's the first word! */
  892.  
  893.     /** spaces before equal sign? **/
  894.  
  895.     while (whitespace(buffer[i])) i++;
  896.     if (buffer[i] == '=') i++;
  897.  
  898.     /** spaces after equal sign? **/
  899.  
  900.     while (whitespace(buffer[i])) i++;
  901.  
  902.     if (buffer[i] != '\0')
  903.       strcpy(word2, (char *) (buffer + i));
  904.     else
  905.       word2[0] = '\0';
  906.  
  907.     /* remove trailing spaces from word2! */
  908.     i = strlen(word2) - 1;
  909.     while(i && (whitespace(word2[i]) || word2[i] == '\n'))
  910.       word2[i--] = '\0';
  911.  
  912.     return(*word2 == '\0' ? -1 : 0 );
  913.  
  914. }
  915.  
  916. expand_env(dest, buffer)
  917. char *dest, *buffer;
  918. {
  919.     /** expand possible metacharacters in buffer and then copy
  920.         to dest... 
  921.  
  922.         BEWARE!! Because strtok() is used on buffer, buffer may be changed.
  923.  
  924.         This routine knows about "~" being the home directory,
  925.         and "$xxx" being an environment variable.
  926.     **/
  927.  
  928.     char  *word, *string, next_word[SLEN];
  929.     
  930.     if (buffer[0] == '/') {
  931.       dest[0] = '/';
  932.       dest[1] = '\0';
  933. /* Added for Apollos - handle //node */
  934.       if (buffer[1] == '/') {
  935.         dest[1] = '/';
  936.         dest[2] = '\0';
  937.       }
  938.     }
  939.     else
  940.       dest[0] = '\0';
  941.  
  942.     string = (char *) buffer;
  943.  
  944.     while ((word = strtok(string, "/")) != NULL) {
  945.       if (word[0] == '$') {
  946.         next_word[0] = '\0';
  947.         if (getenv((char *) (word + 1)) != NULL)
  948.         strcpy(next_word, getenv((char *) (word + 1)));
  949.         if (strlen(next_word) == 0)
  950.           leave(printf(catgets(elm_msg_cat, ElmSet, ElmCantExpandEnvVar,
  951.             "\n\rCan't expand environment variable '%s'.\n\r"),
  952.             word));
  953.       }
  954.       else if (word[0] == '~' && word[1] == '\0')
  955.         strcpy(next_word, home);
  956.       else
  957.         strcpy(next_word, word);
  958.  
  959.       sprintf(dest, "%s%s%s", dest, 
  960.          (strlen(dest) > 0 && lastch(dest) != '/' ? "/":""),
  961.          next_word);
  962.  
  963.       string = (char *) NULL;
  964.     }
  965. }
  966.  
  967. #define on_off(s)    (s == 1? "ON " : "OFF")
  968. dump_rc_results()
  969.     {
  970.     register int i, j, len = 0;
  971.     char buf[SLEN], *s;
  972.  
  973.     for (i = 0; i < NUMBER_OF_SAVEABLE_OPTIONS; i++) {
  974.         extern char *sort_name(), *alias_sort_name();
  975.  
  976.         switch (save_info[i].flags & DT_MASK) {
  977.         case DT_SYN:
  978.         case DT_MLT:
  979.             break;
  980.         case DT_ALT:
  981.             break; /* not dumping addresses to debug file */
  982.         case DT_WEE:
  983.             fprintf(debugfile, "\nAnd we're skipping the following headers:\n\t");
  984.  
  985.             for (len = 8, j = 0; j < weedcount; j++) {
  986.             if (weedlist[j][0] == '*') continue;    /* skip '*end-of-defaults*' */
  987.             if (len + strlen(weedlist[j]) > 80) {
  988.                 fprintf(debugfile, " \n\t");
  989.                 len = 8;
  990.             }
  991.             fprintf(debugfile, "%s  ", weedlist[j]);
  992.             len += strlen(weedlist[j]) + 3;
  993.             }
  994.             fprintf(debugfile, "\n\n");
  995.             break;
  996.  
  997.         default:
  998.             switch (save_info[i].flags&DT_MASK) {
  999.     
  1000.             case DT_STR:
  1001.             s = SAVE_INFO_STR(i);
  1002.             break;
  1003.  
  1004.             case DT_NUM:
  1005.             sprintf(buf, "%d", *SAVE_INFO_NUM(i));
  1006.             s = buf;
  1007.             break;
  1008.  
  1009.             case DT_CHR:
  1010.             sprintf(buf, "%c", *SAVE_INFO_CHR(i));
  1011.             s = buf;
  1012.             break;
  1013.  
  1014.             case DT_BOL:
  1015.             s = on_off(*SAVE_INFO_BOL(i));
  1016.             break;
  1017.  
  1018.             case DT_SRT:
  1019.             s = sort_name(SHORT);
  1020.             break;
  1021.  
  1022.             case DT_ASR:
  1023.             s = alias_sort_name(SHORT);
  1024.             break;
  1025.             }
  1026.  
  1027.             fprintf(debugfile, "%s = %s\n", save_info[i].name, s);
  1028.             break;
  1029.         }
  1030.         }
  1031.     fprintf(debugfile, "\n\n");
  1032. }
  1033.  
  1034. is_it_on(word)
  1035. char *word;
  1036. {
  1037.     /** Returns TRUE if the specified word is either 'ON', 'YES'
  1038.         or 'TRUE', and FALSE otherwise.   We explicitly translate
  1039.         to lowercase here to ensure that we have the fastest
  1040.         routine possible - we really DON'T want to have this take
  1041.         a long time or our startup will be major pain each time.
  1042.     **/
  1043.  
  1044.     static char mybuffer[NLEN];
  1045.     register int i, j;
  1046.  
  1047.     for (i=0, j=0; word[i] != '\0'; i++)
  1048.       mybuffer[j++] = isupper(word[i]) ? tolower(word[i]) : word[i];
  1049.     mybuffer[j] = '\0';
  1050.  
  1051.     return(  (strncmp(mybuffer, "on",   2) == 0) ||
  1052.          (strncmp(mybuffer, "yes",  3) == 0) ||
  1053.          (strncmp(mybuffer, "true", 4) == 0)
  1054.           );
  1055. }
  1056.